/*******************************************************************
This file is part of StartButton.

StartButton is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

StartButton is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with StartButton.  If not, see <http://www.gnu.org/licenses/>.

********************************************************************

StartButton is based on GreenButton by Doug Melton, available at 
http://www.supware.net/

StartButton info and bug reports:
allleimo@interfree.it
*******************************************************************/

// StartButton.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "StartButton.h"
#include "RegistryUtils.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE   hInst;                              // current instance

TCHAR       tcszRun[MAX_LOADSTRING];
TCHAR		tcszHookText[MAX_LOADSTRING];
TCHAR		tcszHookWinKey[MAX_LOADSTRING];


//=============================================================================
//
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPWSTR lpCmdLine, int nCmdShow) {
    MSG msg;
    HWND hwndMain;

    // Initialize this instance.
    hwndMain = InitInstance(hInstance, lpCmdLine, nCmdShow);
    if (hwndMain == 0)
        return 0x10;

    // Application message loop
    while (GetMessage (&msg, NULL, 0, 0)) {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }

    // Instance cleanup
    return TermInstance (hInstance, msg.wParam);
}

//-----------------------------------------------------------------------------
// InitInstance - Instance initialization
//
HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow){
    WNDCLASS wc;
    HWND hWnd;
    TCHAR buffer[MAX_LOADSTRING];

    // Save program instance handle in global variable.
    hInst = hInstance;

    // Allow only one instance of the application.
    hWnd = FindWindow (SZ_APP_NAME, NULL);
    if (hWnd) {
        // This should stop the currently running process
        MessageBox(GetForegroundWindow(), SZ_APP_ABOUT, TEXT("Closing..."), 0);
        PostMessage(hWnd, WM_CLOSE, NULL, NULL);
        return 0;
    }

    // Register application main window class.
    wc.style = 0;                             // Window style
    wc.lpfnWndProc = MainWndProc;             // Callback function
    wc.cbClsExtra = 0;                        // Extra class data
    wc.cbWndExtra = 0;                        // Extra window data
    wc.hInstance = hInstance;                 // Owner handle
    wc.hIcon = NULL;                          // Application icon
    wc.hCursor = NULL;                        // Default cursor
    wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
    wc.lpszMenuName =  NULL;                  // Menu name
    wc.lpszClassName = SZ_APP_NAME;           // Window class name
    if (RegisterClass (&wc) == 0) return 0;

    // Create main window.
    hWnd = CreateWindowEx(WS_EX_NODRAG,       // Ex Style
                         SZ_APP_NAME,         // Window class
                         SZ_APP_NAME,         // Window title
                         WS_SYSMENU,          // Style flags
                                              // don't use WS_VISIBLE.
                                              // Why not? It causes an "error report"
                                              // Why? I don't know.
                         CW_USEDEFAULT,       // x position
                         CW_USEDEFAULT,       // y position
                         CW_USEDEFAULT,       // Initial width
                         CW_USEDEFAULT,       // Initial height
                         NULL,                // Parent
                         NULL,                // Menu, must be null
                         hInstance,           // Application instance
                         NULL);               // Pointer to create
                                              // parameters
    // Return fail code if window not created.
    if (!IsWindow (hWnd)) return 0;

	LoadSetting(tcszHookText, MAX_LOADSTRING, SZ_STARTBUTTON_REG_KEY,
		SZ_HOOK_TEXT, SZ_HOOK_TEXT_DEFAULT);

	LoadSetting(tcszHookWinKey, MAX_LOADSTRING, SZ_STARTBUTTON_REG_KEY,
		SZ_HOOK_WINKEY, SZ_HOOK_WINKEY_DEFAULT);

    // if command line parameter exists, it overrides the registry setting
    if (_tcslen(lpCmdLine) > 0) {
        StringCchCopy(buffer, MAX_LOADSTRING, lpCmdLine);
    }
    else {
        LoadSetting(buffer, MAX_LOADSTRING, SZ_STARTBUTTON_REG_KEY,
            SZ_RUN_KEY, SZ_RUN_DEFAULT);
    }

    if (buffer[0] == '\\') {
        StringCchCopy(tcszRun, MAX_LOADSTRING, buffer);
    }
    else {
        // Look in the localized "Program Files" directory
        SHGetSpecialFolderPath(NULL, tcszRun, CSIDL_PROGRAM_FILES, FALSE);
        StringCchCat(tcszRun, MAX_LOADSTRING, TEXT("\\"));
        StringCchCat(tcszRun, MAX_LOADSTRING, buffer);
    }

    // install hook
    HookStartButton();

    // Standard show and update calls
    ShowWindow(hWnd, SW_MINIMIZE);
    UpdateWindow (hWnd);
    return hWnd;
}


//-----------------------------------------------------------------------------
// TermInstance - Program cleanup
//
int TermInstance (HINSTANCE hInstance, int nDefRC) {
    return nDefRC;
}

//=============================================================================
// Message handling procedures for MainWindow
//

//-----------------------------------------------------------------------------
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam, 
                              LPARAM lParam) {
    
    switch (wMsg) {
        case WM_CLOSE:
        case WM_DESTROY:
            // Unhook any hooks
            UnhookStartButton();

            // Quit
            PostQuitMessage (0);
            return 0;
    }

    return DefWindowProc (hWnd, wMsg, wParam, lParam);
}

//=============================================================================
// Specialized START BUTTON hook functions
//

LONG _oldGreenWindowProc = 0;

LRESULT CALLBACK StartButtonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, 
                                       LPARAM lParam) {

	POINT ptMouseDown = { -1, -1 };
	RECT rStartButton;
	//rStartButton.top = 0;
	//rStartButton.left = 0;
	//rStartButton.bottom = 24;
	//rStartButton.right = 27;

	GetWindowRect(hwnd, &rStartButton);
	if (_tcslen(tcszHookText))
		rStartButton.right = rStartButton.bottom * 2.3;
	else
		rStartButton.right = rStartButton.bottom;

	PROCESS_INFORMATION pi;

	switch (uMsg){
		case WM_LBUTTONDOWN:
			ptMouseDown.x = LOWORD(lParam);
			ptMouseDown.y = LOWORD(wParam);
			
			if (PtInRect(&rStartButton, ptMouseDown)){
				CreateProcess(tcszRun, NULL, NULL, NULL, FALSE, 
				    NULL, NULL, NULL, NULL, &pi);
			}
			else
				goto SKIP;
			break;
		case WM_KEYUP:
				if (wParam == VK_LWIN)
				{
					if (_tcslen(tcszHookWinKey)){
						CreateProcess(tcszRun, NULL, NULL, NULL, FALSE, 
							NULL, NULL, NULL, NULL, &pi);
					}
					else
						goto SKIP;
				}
				else
					goto SKIP;
				break;
		default:
			return CallWindowProc((WNDPROC)_oldGreenWindowProc, hwnd, uMsg, wParam, lParam);
	}
	return 0;

SKIP:
    return CallWindowProc((WNDPROC)_oldGreenWindowProc, hwnd, uMsg, wParam, lParam);
}

void HookStartButton() {
    // attach
    HWND hwnd = FindWindow(TEXT("HHTaskBar"), NULL);  // GREEN_BUTTON_WINDOW_CLASS
    _oldGreenWindowProc = GetWindowLong(hwnd, GWL_WNDPROC);
    LONG result = SetWindowLong(hwnd, GWL_WNDPROC, (LONG)StartButtonWindowProc);
    if (!result) {
        DWORD e = GetLastError();
    }
}

void UnhookStartButton() {
    HWND hwnd = FindWindow(TEXT("HHTaskBar"), NULL);  // GREEN_BUTTON_WINDOW_CLASS
    if (!hwnd || !_oldGreenWindowProc)
        return;

    // detach
    LONG result = SetWindowLong(hwnd, GWL_WNDPROC, _oldGreenWindowProc);
    if (!result) {
        DWORD e = GetLastError();
    }
}
